﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.BusinessLogic.Links
{
    public class EntityLinkDistanceCalc:IEntityLinker
    {
        #region fields
        private Dictionary<string, PropertyInfo> srcProps = new Dictionary<string, PropertyInfo>();
        private Dictionary<string, PropertyInfo> tgtProps = new Dictionary<string, PropertyInfo>();
        Dictionary<string,ArgumentFieldBinding> argBindings=new Dictionary<string, ArgumentFieldBinding>();
        #endregion

        #region Implementation of IEntityLinker

        /// <summary>
        /// 
        /// </summary>
        public List<string> ArgNames
        {
            get
            {
                List<string> argNames=new List<string>();
                argNames.Add("EvidenceFrequencyField");
                return argNames;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="srcEntityType"></param>
        /// <param name="tgtEntityType"></param>
        /// <param name="bindings"></param>
        public void InitBindings(
            Type srcEntityType, Type tgtEntityType, 
            Dictionary<string, ArgumentFieldBinding> bindings)
        {
            this.argBindings = bindings;
            this.srcProps = new Dictionary<string, PropertyInfo>();
            PropertyInfo[] props1 = srcEntityType.GetProperties();
            foreach (PropertyInfo prop in props1)
                this.srcProps.Add(prop.Name, prop);
            this.tgtProps=new Dictionary<string, PropertyInfo>();
            PropertyInfo[] props2 = tgtEntityType.GetProperties();
            foreach (PropertyInfo prop in props2)
                this.tgtProps.Add(prop.Name, prop);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity1"></param>
        /// <param name="entity2"></param>
        /// <returns></returns>
        public double? CalculateDistance(EntityBase entity1, EntityBase entity2)
        {
            int? freq = null;
            try
            {
                if (this.argBindings != null && this.argBindings.ContainsKey(this.ArgNames[0]))
                {
                    ArgumentFieldBinding binding = this.argBindings[this.ArgNames[0]];
                    if (binding.FromSrcEntity)
                    {
                        object evidence = this.srcProps[binding.PropertyName].GetValue(entity1, null);
                        if (evidence != null && evidence.ToString().Length > 0)
                            freq = int.Parse(evidence.ToString());
                    }
                    else
                    {
                        object evidence = this.tgtProps[binding.PropertyName].GetValue(entity2, null);
                        if (evidence != null && evidence.ToString().Length > 0)
                            freq = int.Parse(evidence.ToString());
                    }
                }
                else
                    freq = 1;
            }
            catch(Exception ex)
            {
                ExceptionHandler.HandlesException(ex);
                freq = null;
            }
            if(freq.HasValue && freq.Value>0)
            {
                double distance = Math.Log(100.0/(Math.Min(100, freq.Value)));
                double d = Math.Log(100.0);
                distance = distance/d;
                return distance;
            }
            else
                return null;
        }

        #endregion
    }
}
